package org.biogroovy.search

import groovy.util.logging.Slf4j

import org.biogroovy.net.URLMap


/**
 * This base class provides a template for the creation of new SearchEngine implementations.
 *
 */
@Slf4j
public abstract class AbstractSearchEngine<S> implements ISearchEngine<S> {

	/** The available parameters for the search engine. */
	protected SearchParamSet paramSet = new SearchParamSet();

	/** The result builder responsible for converting POJOs into SearchResult objects. */
	protected IResultBuilder resultBuilder;

	protected ISearchParamMapBuilder paramMapBuilder;


	/**
	 * Constructor.
	 * @param builder the search parameter map builder
	 */
	public AbstractSearchEngine(ISearchParamMapBuilder builder){
		this.paramMapBuilder = builder;
		initSearchParams();
	}

	/**
	 * This method binds search parameters to a URL template and opens an input stream
	 * @param params  a map of parameter names and values
	 * @return an input stream from the specified URL
	 * @throws IOException if there is a problem fetching data from the URL
	 */
	public InputStream bind(Map<String, String> params) throws IOException{
		return bind(getURLTemplate(), params);
	}

	/**
	 * This method binds search parameters to a URL.
	 * @param template  The URL template
	 * @param params  A map of parameters to be appended to the template.
	 * @return an input stream from the specified URL
	 * @throws IOException if there is a problem fetching data from the URL
	 */
	public InputStream bind(String template, Map<String, String> params) throws IOException{
		URLMap urlMap = new URLMap(template, params);
		log.info urlMap.toString()
		return urlMap.toInputStream();
	}

	@Override
	public void doSearch(Search search) throws SearchException{
		ISearchParamMapBuilder builder = getSearchParamMapBuilder();
		Map<String, String> paramMap = builder.createPopulatedParamMap(search.getSearchParams());
		List<S> result = doSearch(paramMap);
		search.setResults(result);
		search.setLastExecuted(new Date());
	}


	@Override
	public SearchParamSet getSearchParameters() {
		return paramSet;
	}

	@Override
	public Search createSearch(){
		Search search = new Search(getName(), "Untitled Search");
		search.setSearchParams(paramSet.clone());

		return search;
	}


	@Override
	public IResultBuilder getResultBuilder(){
		return resultBuilder;
	}

	/**
	 * Sets the result builder
	 * @param resultBuilder the new result builder
	 */
	public void setResultBuilder(IResultBuilder resultBuilder){
		this.resultBuilder = resultBuilder;
	}
	
	@Override
	public ISearchParamMapBuilder getSearchParamMapBuilder() {
		return paramMapBuilder;
	};

	public void setSearchParamMapBuilder(ISearchParamMapBuilder builder){
		this.paramMapBuilder = builder;
	}
	
	/**
	 * Initializes the search parameters.
	 */
	protected abstract void initSearchParams();
}
